package com.transactional.manager.config

import com.atomikos.icatch.jta.UserTransactionManager
import com.atomikos.jdbc.AtomikosDataSourceBean
import com.mysql.cj.jdbc.MysqlXADataSource
import jakarta.transaction.SystemException
import mu.KotlinLogging
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.orm.jpa.JpaTransactionManager
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
import org.springframework.transaction.PlatformTransactionManager
import java.util.*
import javax.sql.DataSource


private val logger = KotlinLogging.logger {}

@Configuration
class DataSourceConfig {

    // MySQL 配置
    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.mysql-user")
    fun mysqlDataSourceProperties(): DataSourceProperties {
        return DataSourceProperties()
    }

    @Primary
    @Bean(name = ["mysqlDataSource"])
    fun mysqlDataSource(@Qualifier("mysqlDataSourceProperties") properties: DataSourceProperties): DataSource {
        val mysqlXADataSource = MysqlXADataSource()
        mysqlXADataSource.setUrl(properties.url)
        mysqlXADataSource.user = properties.username
        mysqlXADataSource.password = properties.password

        val xaDataSource = AtomikosDataSourceBean()
        xaDataSource.uniqueResourceName = "mysql"
        xaDataSource.xaDataSource = mysqlXADataSource
        xaDataSource.minPoolSize = 5
        xaDataSource.maxPoolSize = 20
        return xaDataSource
    }

    @Primary
    @Bean(name = ["mysqlEntityManagerFactory"])
    fun mysqlEntityManagerFactory(@Qualifier("mysqlDataSource") dataSource: DataSource): LocalContainerEntityManagerFactoryBean {
        val em = LocalContainerEntityManagerFactoryBean()
        em.dataSource = dataSource
        em.setPackagesToScan("com.transactional.manager.bean.mysql")
        
        val vendorAdapter = HibernateJpaVendorAdapter()
        em.jpaVendorAdapter = vendorAdapter
        
        val properties = Properties()
        properties["hibernate.hbm2ddl.auto"] = "none"
        properties["hibernate.show_sql"] = "true"
        properties["hibernate.format_sql"] = "true"
        properties["hibernate.transaction.jta.platform"] = "org.hibernate.engine.transaction.jta.platform.internal.AtomikosJtaPlatform"
        properties["jakarta.persistence.transactionType"] = "JTA"
        em.setJpaProperties(properties)
        
        return em
    }

    @Primary
    @Bean(name = ["mysqlTransactionManager"])
    fun mysqlTransactionManager(@Qualifier("mysqlEntityManagerFactory") entityManagerFactory: LocalContainerEntityManagerFactoryBean): PlatformTransactionManager {
        return JpaTransactionManager(entityManagerFactory.getObject()!!)
    }

    @Bean(initMethod = "init", destroyMethod = "close")
    @Throws(SystemException::class)
    fun userTransactionManager(): UserTransactionManager {
        val userTransactionManager = UserTransactionManager()
        userTransactionManager.setTransactionTimeout(300)
        userTransactionManager.forceShutdown = true
        return userTransactionManager
    }

//    @Primary
//    @Bean(name = ["mysqlTransactionManager"])
//    fun mysqlTransactionManager(): JtaTransactionManager {
//        val jtaTransactionManager = JtaTransactionManager()
//        jtaTransactionManager.transactionManager = userTransactionManager()
//        jtaTransactionManager.userTransaction = userTransactionManager()
//        return jtaTransactionManager
//    }

    // PostgreSQL 配置
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.mysql-order")
    fun postgresDataSourceProperties(): DataSourceProperties {
        return DataSourceProperties()
    }

    @Bean(name = ["postgresDataSource"])
    fun postgresDataSource(@Qualifier("postgresDataSourceProperties") properties: DataSourceProperties): DataSource {
        val mysqlXADataSource = MysqlXADataSource()
        mysqlXADataSource.setUrl(properties.url)
        mysqlXADataSource.user = properties.username
        mysqlXADataSource.password = properties.password

        val xaDataSource = AtomikosDataSourceBean()
        xaDataSource.uniqueResourceName = "postgres"
        xaDataSource.xaDataSource = mysqlXADataSource
        xaDataSource.minPoolSize = 5
        xaDataSource.maxPoolSize = 20
        return xaDataSource
    }

    @Bean(name = ["postgresEntityManagerFactory"])
    fun postgresEntityManagerFactory(@Qualifier("postgresDataSource") dataSource: DataSource): LocalContainerEntityManagerFactoryBean {
        val em = LocalContainerEntityManagerFactoryBean()
        em.dataSource = dataSource
        em.setPackagesToScan("com.transactional.manager.bean.postgres")

        val vendorAdapter = HibernateJpaVendorAdapter()
        em.jpaVendorAdapter = vendorAdapter

        val properties = Properties()
        properties["hibernate.hbm2ddl.auto"] = "none"
        properties["hibernate.show_sql"] = "true"
        properties["hibernate.format_sql"] = "true"
        properties["hibernate.transaction.jta.platform"] = "org.hibernate.engine.transaction.jta.platform.internal.AtomikosJtaPlatform"
        properties["jakarta.persistence.transactionType"] = "JTA"
        em.setJpaProperties(properties)

        return em
    }

    @Bean(name = ["postgresTransactionManager"])
//    fun postgresTransactionManager(): JtaTransactionManager {
//        val jtaTransactionManager = JtaTransactionManager()
//        jtaTransactionManager.transactionManager = userTransactionManager()
//        jtaTransactionManager.userTransaction = userTransactionManager()
//        return jtaTransactionManager
//    }
    fun postgresTransactionManager(@Qualifier("postgresEntityManagerFactory") entityManagerFactory: LocalContainerEntityManagerFactoryBean): PlatformTransactionManager {
        return JpaTransactionManager(entityManagerFactory.getObject()!!)
    }
} 